//
//  LevelLayer.m
//
//  Source file for the class where all aspects of the first level
//  of the game is implemented.
//

#import "LevelLayer.h"
#import "Level2Layer.h"
#import "Level3Layer.h"
#import "AppDelegate.h"
#import "MainMenuLayer.h"
#import "GameState.h"
#import "SimpleAudioEngine.h"

static const int kTimerLabelSize = 64;
static const int kHeightOffset = 94;
static const int kTotalObjects = 20;
static const int kTotalWantedObjects = 3;
static const int kDefaultTimer = 60;
static const int kWantedObject = 1;
static const int kUnWantedObject = 0;
static const int kMainMenuButton = 0;
static const int kRetryButton = 1;
static int pauseButton = 0;



@implementation LevelLayer

// returns a scene object containing the current layer
// this essentially loads the "screen" for a
// particular section or part of the game
+(CCScene *) scene
{
	CCScene *scene = [CCScene node];
    LevelLayer *layer = [LevelLayer node];

	[scene addChild: layer];
	
	return scene;
}

// implements the main game logic which is when the player
// touches an object, the score is adjusted based on whether
// the object touched is a wanted or unwanted object
-(void) ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    UITouch *touch = [touches anyObject];
    CGPoint location = [self convertTouchToNodeSpace:touch];
    
    // a list of screen objects to delete. this list is needed as opposed to
    // deleting straight from currentScreenObjects because objective-c does not
    // allow the mutation of a NSMutableArray while it is being enumerated (i.e. iterated over)
    NSMutableArray *screenObjectsToDelete = [[NSMutableArray alloc] init];
    
    // when a touch is registered, go through all the objects currently on screen
    // and if a wanted object is touched, add it to the list of objects to be removed from
    // the screen. if a distraction is touched, it will wiggle and resume its normal action
    for (CCSprite *screenObj in _currentScreenObjects) {
        if (CGRectContainsPoint(screenObj.boundingBox, location)) {
            if (screenObj.tag == kWantedObject) {
                [_scoreLabel setString:[NSString stringWithFormat:@"%d", [[GameState sharedGameState] incScore]]];
                [[SimpleAudioEngine sharedEngine] playEffect:@"146721__fins__menu-click.wav"];
                
                [screenObjectsToDelete addObject:screenObj];
            }
            else if (screenObj.tag == kUnWantedObject) {
                [_scoreLabel setString:[NSString stringWithFormat:@"%d", [[GameState sharedGameState] decScore]]];
                [screenObj runAction:[CCSequence actions:[CCRotateBy actionWithDuration:0.3 angle:20], [CCRotateBy actionWithDuration:0.3 angle:-40], [CCRotateBy actionWithDuration:0.3 angle:20], nil]];
                
                [[SimpleAudioEngine sharedEngine] playEffect:@"171526__fins__old-reactor.wav"];
            }
            
            // this tag assignment is needed to prevent the score from being
            // updated more than once on the same object
            screenObj.tag = 2;
        }
    }
    
    for (CCSprite *objToDelete in screenObjectsToDelete) {
        
        // before an object disappears from screen, show a quick animation of it
        // moving slightly up and then down
        CCMoveTo * moveUp = [CCMoveTo actionWithDuration:0.2
            position:ccp(objToDelete.position.x, objToDelete.position.y + 20)];
        
        CCMoveTo * moveDown = [CCMoveTo actionWithDuration:0.5
            position:ccp(objToDelete.position.x, 0)];
        
        CCCallBlockN * actionMoveDone = [CCCallBlockN actionWithBlock:^(CCNode *node) {
            [_currentScreenObjects removeObject:objToDelete];
            [node removeFromParentAndCleanup:YES];
        }];
        
        [objToDelete runAction:[CCSequence actions:moveUp, moveDown, actionMoveDone, nil]];
    }
    
    [screenObjectsToDelete release];
}

// stops the bird from flying and remove it from the screen
-(void) endFlyBird
{
    _bird.flipX = NO;
    [_bird stopAllActions];
    [_spriteSheet removeChild:_bird cleanup:NO];
}

// every 5 seconds, this method is called to show
// a bird fly from one end of the screen to another.
// the starting position is randomly chosen
-(void) flyBird
{
    CGSize winSize = [[CCDirector sharedDirector] winSize];
    
    int startX = -_bird.contentSize.width / 2;
    int endX = winSize.width + _bird.contentSize.width / 2;
    int birdHeight = 650;
    CGPoint startPos, endPos;
    
    if ((arc4random() % 2) == 1) {
        startPos = ccp(startX, birdHeight);
        endPos = ccp(endX, birdHeight);
        
        // if coming from the left and moving to the right, flip the sprite 
        // since the original bird sprite is facing left
        _bird.flipX = YES;
    }
    else {
        startPos = ccp(endX, birdHeight);
        endPos = ccp(startX, birdHeight);
    }

    _bird.position = startPos;
    
    CCAction *flyAction = [CCRepeatForever actionWithAction:
                       [CCAnimate actionWithAnimation:_flyAnim]];
    
    CCAction *moveAction = [CCSequence actions:
        [CCMoveTo actionWithDuration:4.0 position:endPos],
        [CCCallFunc actionWithTarget:self selector:@selector(endFlyBird)], nil];
    
    [_bird runAction:flyAction];
    [_bird runAction:moveAction];
    [_spriteSheet addChild:_bird];
}

// this is the method that handles the button press functionality of the alert box
// that pops up when the game ends
-(void) alertView:(UIAlertView *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
    [[CCDirector sharedDirector] resume];
    
    // the user presses the first button main menu which aborts the game 
    // the score and data from that game are saved
    if (buttonIndex == kMainMenuButton) {
        
        [[GameState sharedGameState] setState:@"totalScore" value:[[GameState sharedGameState] getScore]+[[[GameState sharedGameState] getState:@"totalScore"] integerValue]];
        [[GameState sharedGameState] setState:@"totalGamesPlayed" value:1+[[[GameState sharedGameState] getState:@"totalGamesPlayed"] integerValue]];
        [[GameState sharedGameState] saveHighestScore];
        [[GameState sharedGameState] resetScore];
        [[GameState sharedGameState] resetCompletion];
        [[CCDirector sharedDirector] replaceScene:[MainMenuLayer scene]];
    }
    // the user presses the second button, and no time is remaining,
    // implies the user has lost the game, the score and data are saved
    else if (buttonIndex == kRetryButton && _currentTime == 0) {
        
        GameState *gameState = [GameState sharedGameState];
        [gameState setState:@"totalScore" value:[[GameState sharedGameState] getScore]+[[[GameState sharedGameState] getState:@"totalScore"] integerValue]];
        [gameState setState:@"totalGamesPlayed" value:1+[[[GameState sharedGameState] getState:@"totalGamesPlayed"] integerValue]];
        [[GameState sharedGameState] saveHighestScore];
        [gameState resetScore];
        [gameState resetCompletion];
        [[CCDirector sharedDirector] replaceScene:[LevelLayer scene]];
    }
    // the user presses the second button with time remaining
    // implies that the user wants to resume the game
    else if (buttonIndex == kRetryButton && _currentTime != 0 && pauseButton != 0){
        pauseButton = 0;
    }
    
    // the user presses the second button with time remaining, implies that
    // the user has the required amount of points and wants to progress to next level
    else if (buttonIndex == kRetryButton && _currentTime != 0) {
        [[GameState sharedGameState] incCompletion];
        [[CCDirector sharedDirector] replaceScene:[Level2Layer scene]];
    }
}

// this method is called every 1 second to update the amount of
// time left for this level
-(void) gameTimer
{
    [_timeLabel setString:[NSString stringWithFormat:@"%d", --_currentTime]];
    
    if (_currentTime == 0) {
        [[CCDirector sharedDirector] pause];
        [[GameState sharedGameState] setState:@"totalTimePlayed" value:60-_currentTime+[[[GameState sharedGameState] getState:@"totalTimePlayed"] integerValue]];
        UIAlertView *dialog = [[UIAlertView alloc] init];
        [dialog setDelegate:self];
        [dialog setTitle:@"Times Up!"];
        [dialog setMessage:[NSString stringWithFormat:@"Your high score is: %d", [[GameState sharedGameState] getScore]]];
        [dialog addButtonWithTitle:@"Main Menu"];
        [dialog addButtonWithTitle:@"Retry"];
        [dialog show];
        [dialog release];
    }
}

// this method is called every half second to check if 5 points has been
// accumulated in this level, in which case the player moves on to the next level
-(void) scoreCheck
{
    if ([[GameState sharedGameState] getScore] == 5*([[GameState sharedGameState] getCompletion] + 1)) {
        [[CCDirector sharedDirector] pause];
        
        // check if the time taken to complete this level is a record best 
        // time for the user, if so, update the best time
        int bestTime = [[[GameState sharedGameState] getState:@"level1BestTime"] integerValue];
        if (60-_currentTime < bestTime) {
            [[GameState sharedGameState] setState:@"level1BestTime" value:60-_currentTime];
        }
        
        // adds the time taken to complete this level to the total time played
        [[GameState sharedGameState] setState:@"totalTimePlayed" value:60-_currentTime+[[[GameState sharedGameState] getState:@"totalTimePlayed"] integerValue]];
        
        UIAlertView *dialog = [[UIAlertView alloc] init];
        [dialog setDelegate:self];
        [dialog setTitle:@"Congratulations!"];
        [dialog setMessage:[NSString stringWithFormat:@"You've reached the next level!"]];
        [dialog addButtonWithTitle:@"Main Menu"];
        [dialog addButtonWithTitle:@"Continue"];
        [dialog show];
        [dialog release];
    }
}

-(void)pausePressed
{
        pauseButton = 1;
        [[CCDirector sharedDirector] pause];
        UIAlertView *dialog = [[UIAlertView alloc] init];
        [dialog setDelegate:self];
        [dialog setTitle:@"Level 1"];
        [dialog setMessage:[NSString stringWithFormat:@"You have paused the game"]];
        [dialog addButtonWithTitle:@"Main Menu"];
        [dialog addButtonWithTitle:@"Resume"];
        [dialog show];
        [dialog release];
    

    
    
}


// this method is called every 2 seconds and adds a car that can
// be tapped by the player
-(void) addLevelObjects
{
    NSString *randomPick;
    CCSprite *distraction;
    int wantedChance = arc4random() % 2;
    
    // randomly determine if next object is a distraction or a wanted object
    if (wantedChance == 1){
        randomPick = [_wantedObjects objectAtIndex:(arc4random() % kTotalWantedObjects)];
        distraction = [CCSprite spriteWithFile:randomPick];
        distraction.tag = [_wantedObjects containsObject:randomPick] ? 1 : 0;
    }
    else{
        randomPick = [_levelObjects objectAtIndex:(arc4random() % kTotalObjects)];
        distraction = [CCSprite spriteWithFile:randomPick];
        distraction.tag = [_wantedObjects containsObject:randomPick] ? 1 : 0;
    }
    
    [_currentScreenObjects addObject:distraction];
    
    int direction = arc4random() % 2;
    int actualX;
    int actualY;
    
    CCSprite *wheelL = [CCSprite spriteWithFile:@"car2_tire.png"];
    CCSprite *wheelR = [CCSprite spriteWithFile:@"car2_tire.png"];
    
    CGSize winSize = [[CCDirector sharedDirector] winSize];
    
    // direction of the car is randomly determined and can either be facing
    // left or facing right while moving
    if (direction==1){
        distraction.flipX = YES;
        actualX = -distraction.contentSize.width / 2;
        actualY = 200;
        distraction.position = ccp(actualX, actualY);
        wheelL.position = ccp(30,10);
        wheelR.position = ccp(120,10);
    }
    else{
        actualX = winSize.width + distraction.contentSize.width / 2 / 2;
        actualY = 330;
        distraction.position = ccp(actualX, actualY);
        wheelL.position = ccp(40,10);
        wheelR.position = ccp(130,10);
    }
    
    // the z values have to be assigned so that the body
    // of the car overlaps the wheels
    [self addChild:distraction z:2];
    [distraction addChild:wheelL z:-1];
    [distraction addChild:wheelR z:-1];
    
    float screenDuration = (3.0-0.3*floor([[GameState sharedGameState] getCompletion]/3));
    if (screenDuration < 0.6){
        screenDuration = 0.6;
    }
    
    
    
    CCMoveTo * actionMoveRight = [CCMoveTo actionWithDuration:screenDuration
        position:ccp(winSize.width + distraction.contentSize.width / 2, actualY)];
    
    CCMoveTo * actionMoveLeft = [CCMoveTo actionWithDuration:screenDuration
        position:ccp(-distraction.contentSize.width / 2, actualY)];
    
    CCCallBlockN * actionMoveDone = [CCCallBlockN actionWithBlock:^(CCNode *node) {
        [_currentScreenObjects removeObject:distraction];
        [node removeFromParentAndCleanup:YES];
    }];
    
    // rotate wheels repeatedly depending on which direction was chosen
    if (direction == 1){
        [distraction runAction:[CCSequence actions:actionMoveRight, actionMoveDone, nil]];
        [wheelL runAction:[CCRepeatForever actionWithAction:[CCRotateBy actionWithDuration:5.0 angle:360]]];
        [wheelR runAction:[CCRepeatForever actionWithAction:[CCRotateBy actionWithDuration:5.0 angle:360]]];
    }
    else{
        [distraction runAction:[CCSequence actions:actionMoveLeft, actionMoveDone, nil]];
        [wheelL runAction:[CCRepeatForever actionWithAction:[CCRotateBy actionWithDuration:5.0 angle:-360]]];
        [wheelR runAction:[CCRepeatForever actionWithAction:[CCRotateBy actionWithDuration:5.0 angle:-360]]];
    }
}

// initialize this layer; this includes initializing several instance variables
// and initializing the sprites needed for this scene
-(id) init
{
	if( (self = [super init]) ) {
        
        // list of all images that we have for this level
        _levelObjects = [[NSArray arrayWithObjects:@"car_black.png", @"car_blue.png", @"car_darkblue.png", @"car_darkgreen.png", @"car_darkred.png", @"car_green.png", @"car_orange.png", @"car_pink.png", @"car_purple.png", @"car_red.png", @"car_white.png", @"car_yellow.png", @"van_black.png", @"van_blue.png", @"van_darkblue.png", @"van_gray.png", @"van_green.png", @"van_red.png", @"van_white.png", @"van_yellow.png", nil] retain];
        
        _currentScreenObjects = [[NSMutableArray alloc] init];
        _wantedObjects = [[NSMutableArray alloc] init];
        
        CGSize winSize = [[CCDirector sharedDirector] winSize];
        int posMultiplier = 1;
        int wantedPosX;
        int wantedPosY;
        
        // randomly populate the list of wanted objects until there are three elements in total.
        // after each pick, display the object at the bottom of the screen
        while(_wantedObjects.count != kTotalWantedObjects) {
            NSString *randomPick = [_levelObjects objectAtIndex:(arc4random() % kTotalObjects)];
            
            if ([_wantedObjects containsObject:randomPick]) {
                continue;
            }
            else {
                [_wantedObjects addObject:randomPick];
                CCSprite *wantedSprite = [CCSprite spriteWithFile:randomPick];
                wantedPosX = winSize.width/2 + 200 * (posMultiplier-(kTotalWantedObjects+1)/2);
                wantedPosY = 70;
                wantedSprite.position = ccp( wantedPosX, wantedPosY);
                wantedSprite.flipX = YES;
                CCSprite *wheelLeft = [CCSprite spriteWithFile:@"car2_tire.png"];
                CCSprite *wheelRight = [CCSprite spriteWithFile:@"car2_tire.png"];
                wheelLeft.position = ccp( wantedPosX-49, wantedPosY-35);
                wheelRight.position = ccp( wantedPosX+40, wantedPosY-35);
                ++posMultiplier;
                [self addChild:wantedSprite z:2];
                [self addChild:wheelLeft z:1];
                [self addChild:wheelRight z:1];
            }
        }
        
        CCSprite *bg = [CCSprite spriteWithFile:@"level1Background.png"];
        bg.position = ccp(winSize.width / 2, winSize.height / 2);
        [self addChild:bg z:0];
        
        _currentTime = kDefaultTimer;
        _timeLabel = [CCLabelTTF labelWithString:[NSString stringWithFormat:@"%d", kDefaultTimer] fontName:@"Marker Felt" fontSize:kTimerLabelSize];
		_timeLabel.position =  ccp(winSize.width - kTimerLabelSize, winSize.height - kTimerLabelSize);
        _timeLabel.color = ccc3(0, 0, 0);
		[self addChild: _timeLabel];
        
        _scoreLabel = [CCLabelTTF labelWithString:[NSString stringWithFormat:@"%d", [[GameState sharedGameState] getScore]] fontName:@"Marker Felt" fontSize:kTimerLabelSize];
        _scoreLabel.position = ccp(kTimerLabelSize / 2, winSize.height - kTimerLabelSize);
        _scoreLabel.color = ccc3(0, 0, 255);
        [self addChild: _scoreLabel];
        
        // cache the sprite file for the bird
        [[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:@"animBird.plist"];
        _spriteSheet = [CCSpriteBatchNode batchNodeWithFile:@"animBird.png"];
        [self addChild:_spriteSheet];
        
        _flyAnimFrames = [[NSMutableArray array] retain];
        for (int i = 1; i <= 3; ++i) {
            [_flyAnimFrames addObject:
             [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:
              [NSString stringWithFormat:@"bluejay-sprite-0%d-iPad.png", i]]];
        }
        
        _flyAnim = [[CCAnimation animationWithSpriteFrames:_flyAnimFrames delay:0.1f] retain];
        _bird = [[CCSprite spriteWithSpriteFrameName:@"bluejay-sprite-01-iPad.png"] retain];
        
        CCMenuItemImage *pauseBtn = [CCMenuItemImage itemWithNormalImage:@"pausebutton.png"
                                                          selectedImage:@"pausebutton.png" target:self selector:@selector(pausePressed)];
        
        //the pause button will be placed on the bottom right of the screen
        CCMenu *pauseMenu = [CCMenu menuWithItems:pauseBtn, nil];
        
        pauseMenu.position = ccp(950, 62.5);
        
        [self addChild:pauseMenu];

        
        self.touchEnabled = YES;
        [self schedule:@selector(flyBird) interval:5.0];
        [self schedule:@selector(gameTimer) interval:1.0];
        [self schedule:@selector(scoreCheck)];
        [self schedule:@selector(addLevelObjects) interval:2.0];
	}

	return self;
}

// deallocate all memory used
- (void) dealloc
{
    [_levelObjects release];
    [_wantedObjects release];
    [_currentScreenObjects release];
    [_flyAnimFrames release];
    [_flyAnim release];
    [_bird release];
    _levelObjects = nil;
    _wantedObjects = nil;
    _currentScreenObjects = nil;
    _flyAnimFrames = nil;
    _flyAnim = nil;
    _bird = nil;
	[super dealloc];
}

#pragma mark GameKit delegate

@end
